home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / EventLoop.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  7.6 KB  |  248 lines  |  [TEXT/CWIE]

  1. // EventLoop.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. /** Class for managing a sequence of Events. In general, you never create
  10.   * an EventLoop.  Instead you retrieve the main one from the Application.
  11.   * @see Application#eventLoop
  12.   * @note 1.0 protected code around thread priority switching
  13.   * @note 1.0 added internal calls for will/didProcessEvent
  14.   * @note 1.1 Added application ivar for valid timer code
  15.   */
  16. public class EventLoop implements Runnable {
  17.     Vector events = new Vector();
  18.     Thread mainThread;
  19.     private boolean shouldRun=false;
  20.     static boolean letAwtThreadRun = true;
  21.     Application application;
  22.  
  23.     /** Constructs an EventLoop. */
  24.     public EventLoop() {
  25.         super();
  26.     }
  27.  
  28.     /** Places <b>anEvent</b> on the EventLoop's event queue.
  29.      */
  30.     public void addEvent(Event anEvent) {
  31.         synchronized (events) {
  32.             events.addElement(anEvent);
  33.             events.notify();
  34.         }
  35.     }
  36.  
  37.     final void letAWTThreadRun() {
  38.         if (letAwtThreadRun) {
  39.             Thread thread;
  40.             int priority, tmpPriority;
  41.  
  42.             if (!shouldProcessSynchronously()) {
  43.                 return;
  44.             }
  45.  
  46.             thread = Thread.currentThread();
  47.             priority = thread.getPriority();
  48.             tmpPriority = priority - 1;
  49.  
  50.             if (tmpPriority < Thread.MIN_PRIORITY)
  51.                 tmpPriority = Thread.MIN_PRIORITY;
  52.  
  53.             try {
  54.                 thread.setPriority(tmpPriority);
  55.                 Thread.yield();
  56.                 thread.setPriority(priority);
  57.             } catch (SecurityException e) {
  58.                 letAwtThreadRun = false;
  59.             }
  60.         }
  61.     }
  62.  
  63.     /** Removes all occurrences of <b>anEvent</b> from the event queue.
  64.       */
  65.     public void removeEvent(Event anEvent) {
  66.         synchronized (events) {
  67.             events.removeElement(anEvent);
  68.         }
  69.     }
  70.  
  71.     /** Allows an object to search or modify the EventLoop's Vector of
  72.       * outstanding events.  Upon calling <b>filterEvents()</b>, <b>filter</b>
  73.       * receives a <b>filterEvents()</b> message, with
  74.       * the events Vector as an argument.  The EventLoop locks the Vector
  75.       * before calling the filter's <b>filterEvents()</b> method, so no other
  76.       * threads can modify its contents.  This method returns the results of
  77.       * the filter's <b>filterEvents()</b> method.
  78.       * @see EventFilter#filterEvents
  79.       */
  80.     public Object filterEvents(EventFilter filter) {
  81.         Object returnValue;
  82.  
  83.         letAWTThreadRun();
  84.  
  85.         synchronized (events) {
  86.             returnValue = filter.filterEvents(events);
  87.             events.notify();
  88.         }
  89.         return returnValue;
  90.     }
  91.  
  92.     /** Removes and returns the next Event from the EventLoop's event queue.
  93.       */
  94.     public Event getNextEvent() {
  95.         Event        nextEvent = null;
  96.  
  97.         synchronized(events) {
  98.             while (events.count() == 0) {
  99.                 try {
  100.                     events.wait();
  101.                 } catch (InterruptedException e) {
  102.                 }
  103.             }
  104.             nextEvent = (Event)events.removeFirstElement();
  105.         }
  106. // ALERT! THIS SHOULD NOT HAPPEN
  107. //        if (nextEvent == null) {
  108. //          print something bad here
  109. //        }
  110.         return nextEvent;
  111.     }
  112.  
  113.  
  114.     /** Returns the next Event from the EventLoop's event queue, but does
  115.       * not remove it.
  116.       */
  117.     public Event peekNextEvent() {
  118.         Event        nextEvent;
  119.  
  120.         letAWTThreadRun();
  121.  
  122.         synchronized (events) {
  123.             nextEvent = (Event)events.firstElement();
  124.         }
  125.  
  126.         return nextEvent;
  127.     }
  128.  
  129.     /** This method is called to process each Event as the EventLoop removes
  130.       * it from its queue.
  131.       */
  132.     public void processEvent(Event nextEvent) {
  133.         Object lock = nextEvent.synchronousLock();
  134.         Application application = Application.application();
  135.  
  136.         // ALERT!  May want a try/catch here so that didProcessEvent() can
  137.         // clean up.
  138.  
  139.         application.willProcessInternalEvent(nextEvent);
  140.         application.willProcessEvent(nextEvent);
  141.  
  142.         nextEvent.processor().processEvent(nextEvent);
  143.         if (lock != null) {
  144.             synchronized (lock) {
  145.                 nextEvent.clearSynchronousLock();
  146.                 lock.notify();
  147.             }
  148.         }
  149.  
  150.         application.didProcessEvent(nextEvent);
  151.         application.didProcessInternalEvent(nextEvent);
  152.     }
  153.  
  154.     /** Runnable interface method implemented to process Events as they
  155.       * appear in the queue.
  156.       */
  157.     public void run() {
  158.         Event   nextEvent, secondEvent;
  159.  
  160.         synchronized (this) {
  161.             if (mainThread != null) {
  162.                 throw new InconsistencyException(
  163.                                     "Only one thread may run an EventLoop");
  164.             }
  165.  
  166.             mainThread = Thread.currentThread();
  167.             shouldRun = true;
  168.         }
  169.         while (shouldRun) {
  170.             /* remove the next event from the queue and release it */
  171.             nextEvent = getNextEvent();
  172.             if (shouldRun) { /* shouldRun might have changed during
  173.                                 getNextEvent() */
  174.                 try {
  175.                     processEvent(nextEvent);
  176.                 } catch (Exception e) {
  177.                     System.err.println(
  178.                         Application.application().exceptionHeader());
  179.                     e.printStackTrace(System.err);
  180.                     System.err.println("Restarting EventLoop.");
  181.                 }
  182.             }
  183.         }
  184.  
  185.         /* ALERT: We may want to wakeup any thread
  186.          * waiting for an event to be processed.
  187.          * This is risky though since the event has not
  188.          * been really processed.
  189.          */
  190.  
  191.         synchronized (this) {
  192.             mainThread = null;
  193.         }
  194.     }
  195.  
  196.     /** Stops the EventLoop once control returns from processing the current
  197.       * Event. This method might be called from the AWT thread.
  198.       */
  199.     synchronized public void stopRunning() {
  200.         Event stopEvent = new ApplicationEvent();
  201.  
  202.         shouldRun = false; /* Set shouldRun to false to make sure that
  203.                               we don't compute any other events
  204.                             */
  205.         stopEvent.type = ApplicationEvent.STOP;
  206.         addEvent(stopEvent);
  207.     }
  208.  
  209.     /** Returns <b>true</b> if the EventLoop is currently running. */
  210.     public synchronized boolean isRunning() {
  211.         return shouldRun;
  212.     }
  213.  
  214.     synchronized boolean shouldProcessSynchronously() {
  215.         return (mainThread == null || Thread.currentThread() == mainThread);
  216.     }
  217.  
  218.     /** Adds <b>event</b> to the EventLoop's event queue and waits for the main
  219.       * application thread to process it.  This method should only be called
  220.       * from within threads <i>other than</i> the main thread.
  221.       */
  222.     public void addEventAndWait(Event event) {
  223.         if (Thread.currentThread() == mainThread) {
  224.             throw new InconsistencyException(
  225.                         "Can't call addEventAndWait from " +
  226.                                 "within the EventLoop's main thread");
  227.         } else {
  228.             Object lock = event.createSynchronousLock();
  229.  
  230.             synchronized (lock) {
  231.                 addEvent(event);
  232.                 while (event.synchronousLock() != null) {
  233.                     try {
  234.                         lock.wait();
  235.                     }
  236.                     catch (InterruptedException e) {
  237.                     }
  238.                 }
  239.             }
  240.         }
  241.     }
  242.  
  243.     /** Returns the EventLoop's String representation. */
  244.     public synchronized String toString() {
  245.         return events.toString();
  246.     }
  247. }
  248.